#include "string.h"

namespace wyx
{
	std::ostream& operator<<(std::ostream& _cout, string& s)
	{
		for (size_t i = 0; i < s.size(); ++i)
		{
			_cout << s[i];
		}

		return _cout;
	}
	//iterator
	string::iterator string::begin()
	{
		return _str;
	}

	string::iterator string::end()
	{
		return _str + _size;
	}

	string::const_iterator string::begin()const
	{
		return _str;
	}

	string::const_iterator string::end()const
	{
		return _str + _size;
	}

	//modify
	void string::push_back(char c)
	{
		if (_size == _capacity)
			reserve(2 * _capacity);

		_str[_size++] = c;
		_str[_size] = '\0';
	}

	string& string::operator+=(char c)
	{
		push_back(c);
		return *this;
	}

	void string::append(const char* str)
	{
		assert(nullptr != str);

		size_t old_size = _size;
		size_t new_size = _size + strlen(str);
		if (new_size >= _capacity)
		{
			reserve(new_size);
			memcpy(_str + old_size, str, strlen(str) + 1);
		}

		_size = new_size;
	}

	string& string::operator+=(const char* str)
	{
		assert(nullptr != str);

		append(str);

		return *this;
	}

	void string::clear()
	{
		_size = 0;
		_str[0] = '\0';
	}

	void string::swap(string& s)
	{
		std::swap(_str, s._str);
		std::swap(_size, s._size);
		std::swap(_capacity, s._capacity);
	}

	const char* string::c_str()const
	{
		return _str;
	}

	//capacity
	size_t string::size()const
	{
		return _size;
	}
	
	size_t string::capacity()const
	{
		return _capacity;
	}

	bool string::empty()const
	{
		return _size == 0;
	}

	void string::resize(size_t n, char c)
	{
		if (n > _size)
		{
			size_t k = n - _size;

			while (k < npos)
			{
				push_back(c);
				k--;
			}
		} 
		else
		{
			_str[n] = '\0';
		}

		_size = n;
	}

	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			size_t new_capacity = n > 2 * _capacity ? n : 2 * _capacity;
			char* tmp = new char[new_capacity + 1];

			memcpy(tmp, _str, _size + 1);
			delete[] _str;
			_str = tmp;
			_capacity = new_capacity;
		}
	}


	//access
	char& string::operator[](size_t index)
	{
		assert(index >= 0 && index < _size);

		return _str[index];
	}

	const char& string::operator[](size_t index)const
	{
		assert(index >= 0 && index < _size);

		return _str[index];
	}

	//relation operator
	bool string::operator==(const string& s)const
	{
		if (_size != s._size)
			return false;

		for (size_t i = 0; i < _size; ++i)
		{
			if (_str[i] != s._str[i])
				return false;
		}
		
		return true;
	}

	bool string::operator>(const string& s)const
	{
		if (*this == s)
			return false;

		size_t min_size = _size > s._size ? s._size : _size;
		
		for (size_t i = 0; i < min_size; ++i)
		{
			if (_str[i] <= s._str[i])
				return false;
		}

		if (min_size == _size)
			return false;

		return true;
	}

	bool string::operator>=(const string& s)const
	{
		return *this == s || *this > s;
	}

	bool string::operator<(const string& s)const
	{
		return !(*this >= s);
	}

	bool string::operator<=(const string& s)const
	{
		return !(*this > s);
	}

	bool string::operator!=(const string& s)const
	{
		return !(*this == s);
	}


	/////
	size_t string::find(char c, size_t pos) const
	{
		assert(pos >= 0 && pos < _size);

		for (size_t i = pos; pos < _size; ++i)
		{
			if (_str[i] == c)
				return i;
		}
		
		return npos;
	}

	size_t string::find(const char* s, size_t pos) const
	{
		assert(pos >= 0 && pos < _size);

		const char* spos = strstr(_str + pos, s);

		if (spos)
		{
			return spos - _str;
		}

		return npos;
	}

	string string::substr(size_t pos, size_t len)const
	{
		assert(pos >= 0 && pos < _size);

		size_t new_size = _size - pos >= len ? len : _size - pos;
		string tmp;

		tmp._str = new char[new_size + 1];
		tmp._size = tmp._capacity = new_size;
		memcpy(tmp._str, _str + pos, tmp._size);
		tmp._str[tmp._size] = '\0';

		return tmp;
	}
	string::iterator string::insert(iterator p, char c)
	{
		assert(p >= begin() && p < end());

		if (_size + 1 >= _capacity)
			reserve(_size + 1);

		size_t pos = p - begin();
		for (size_t i = _size + 1; i >= pos + 1; --i)
		{
			_str[i] = _str[i - 1];
		}

		_str[pos] = c;
		

		return _str + pos;
	}

	string& string::insert(size_t pos, const char* str)
	{
		assert(str != nullptr && pos >= 0 && pos < _size);

		size_t len = strlen(str);
		size_t new_size = _size + len;

		if (new_size >= _capacity)
			reserve(new_size);
		_size = _size + len;
		
		for (size_t i = _size; i >= pos + len; --i)
		{
			_str[i] = _str[i - len];
		}
		
		for (size_t i = pos, j = 0; j < len; ++i, ++j)
		{
			_str[i] = str[j];
		}

		return *this;
	}

	string::iterator string::erase(iterator p)
	{
		assert(p >= begin() && p < end());

		size_t pos = p - begin();
		for (size_t i = pos; i < _size; ++i)
		{
			_str[i] = _str[i + 1];
		}

		return begin() + pos;

	}

	string& string::erase(size_t pos, size_t len)
	{
		assert(pos >= 0 && pos < _size);

		if (_size - pos <= len)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			for (size_t i = pos; i < _size; ++i)
			{
				_str[i] = _str[i + len];
			}

			_size = _size - len;
		}

		return *this;
	}
}
	
